#pragma once
#include <atomic>
#include <vector>
namespace xncc {
namespace msg {

    struct RingBufferOptimize
    {
        std::vector<int> data_                         = {};
        alignas(64) std::atomic<std::size_t> read_idx_ = {0};
        alignas(64) std::size_t write_idx_cached_;
        alignas(64) std::atomic<std::size_t> write_idx_ = {0};
        alignas(64) std::size_t read_idx_cached_;

        RingBufferOptimize(std::size_t cap) : data_(cap, 0) {}

        bool push(int val)
        {
            auto const write_idx      = write_idx_.load(std::memory_order_relaxed);
            auto       next_write_idx = write_idx + 1;
            if (next_write_idx == data_.size()) {
                next_write_idx = 0;
            }
            if (next_write_idx == read_idx_cached_) {
                read_idx_cached_ = read_idx_.load(std::memory_order_acquire);
                if (next_write_idx == read_idx_cached_) {
                    return false;
                }
            }
            data_[write_idx] = val;
            write_idx_.store(next_write_idx, std::memory_order_release);
            return true;
        }

        bool pop(int& val)
        {
            auto const read_idx = read_idx_.load(std::memory_order_relaxed);
            if (read_idx == write_idx_cached_) {
                write_idx_cached_ = write_idx_.load(std::memory_order_acquire);
                if (read_idx == write_idx_cached_) {
                    return false;
                }
            }
            val                = data_[read_idx];
            auto next_read_idx = read_idx + 1;
            if (next_read_idx == data_.size()) {
                next_read_idx = 0;
            }
            read_idx_.store(next_read_idx, std::memory_order_release);
            return true;
        }
    };
}  // namespace msg
}  // namespace xncc